package com.lengtouzai.databaseexp.view.register;


import com.lengtouzai.databaseexp.entity.FriendGroup;
import com.lengtouzai.databaseexp.entity.User;
import com.lengtouzai.databaseexp.security.RegistrationService;
import com.lengtouzai.databaseexp.view.login.LoginView;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import io.jmix.core.DataManager;
import io.jmix.core.Metadata;
import io.jmix.flowui.Notifications;
import io.jmix.flowui.ViewNavigators;
import io.jmix.flowui.component.textfield.JmixPasswordField;
import io.jmix.flowui.component.textfield.TypedTextField;
import io.jmix.flowui.exception.ValidationException;
import io.jmix.flowui.kit.component.button.JmixButton;
import io.jmix.flowui.model.InstanceContainer;
import io.jmix.flowui.view.*;
import io.jmix.securityflowui.password.PasswordValidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;

@Route(value = "register")
@ViewController("exp_RegisterView")
@ViewDescriptor("register-view.xml")
@AnonymousAllowed
public class RegisterView extends StandardView {
    private static final Logger log = LoggerFactory.getLogger(RegisterView.class);
    @Autowired
    protected DataManager dataManager;
    @ViewComponent
    private JmixPasswordField password;
    @ViewComponent
    private JmixPasswordField confirmPassword;
    @ViewComponent
    private InstanceContainer<User> userDc;
    @ViewComponent
    private TypedTextField<String> username;
    @Autowired
    private Notifications notifications;
    @Autowired
    private Metadata metadata;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private PasswordValidation passwordValidation;
    @Autowired
    private RegistrationService registrationService;
    @Autowired
    private ViewNavigators viewNavigators;

    @Subscribe
    public void onReady(final ReadyEvent event) {
        // create new user instance
        userDc.setItem(metadata.create(User.class));
    }

    @Install(to = "confirmPassword", subject = "validator")
    private void confirmPasswordValidator(final String value) {
        if (!value.equals(password.getValue())) {
            log.error("Passwords do not match");
            throw new ValidationException("Passwords do not match");
        }
    }

    @Install(to = "username", subject = "validator")
    private void usernameValidator(final Object value) {
        dataManager.load(User.class)
                .query("select u from exp_User u where u.username = :username")
                .parameter("username", value).optional().ifPresent(users -> {
                    log.error("User already exists");
                    throw new ValidationException("User already exists");
                });
    }

    @Subscribe(id = "registerButton", subject = "clickListener")
    public void onRegisterButtonClick(final ClickEvent<JmixButton> event) {
        if (username.isInvalid() || password.isInvalid() || confirmPassword.isInvalid()) {
            log.error("Invalid user information");
            notifications.create("Invalid user information").withType(Notifications.Type.ERROR).show();
            return;
        }
        User user = userDc.getItem();
        user.setPassword(passwordEncoder.encode(password.getValue()));
        List<String> errors = passwordValidation.validate(user, password.getValue());
        if (!errors.isEmpty()) {
            notifications.create(String.join("\n", errors))
                    .withPosition(Notification.Position.BOTTOM_END)
                    .show();
        } else {
            registrationService.register(user);
            // create default friend group
            FriendGroup defaultGroup = dataManager.create(FriendGroup.class);
            defaultGroup.setBelongs(user);
            defaultGroup.setName("Default Group");
            user.setFriendGroups(List.of(defaultGroup));
            dataManager.save(defaultGroup);
            dataManager.save(user);
            viewNavigators.view(this, LoginView.class).navigate();
        }
    }

    @Subscribe(id = "cancelButton", subject = "clickListener")
    public void onCancelButtonClick(final ClickEvent<JmixButton> event) {
        viewNavigators.view(this, LoginView.class).navigate();
    }
}